package util;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import sentData.Lecture;

public class LectureFilter {

	/**
	 * ex. func(lectures, -2) => get lectures 2 weeks back in a list of week
	 * days.
	 * 
	 * @param lectures
	 *            all lectures that need to be filtered
	 * @param weekShift
	 *            0 - current week
	 * @return Week(DayOfWeek(Lecture))
	 */
	public static List<List<Lecture>> filterLectures(List<Lecture> lectures,
			int weekShift) {
		Calendar calendar = new GregorianCalendar();
		calendar.add(Calendar.WEEK_OF_YEAR, weekShift);
		setToFirstDayOfWeek(calendar);

		int[] weekDaysDatesAsInts = computeWeekDaysDatesAsInts(calendar);

		List<List<Lecture>> result = new ArrayList<List<Lecture>>(7);
		for (int i = 0; i < 7; i++) {
			result.add(new ArrayList<Lecture>());
		}

		for (Lecture lecture : lectures) {
			int lectureDate = lecture.getDate();
			boolean dateIsInInterval = dateIsInInterval(weekDaysDatesAsInts, lectureDate);
			if (dateIsInInterval) {
				addLectureToCorrespondingResultList(lecture, result,
						weekDaysDatesAsInts, lectureDate);
			}
		}
		//NOTE if time is used, need to sort all lists by it
		return result;
	}

	private static void addLectureToCorrespondingResultList(Lecture lecture,
			List<List<Lecture>> result, int[] weekDaysDatesAsInts,
			int lectureDate) {
		for (int i = 0; i < 7; i++) {
			if (weekDaysDatesAsInts[i] == lectureDate) {
				result.get(i).add(lecture);
				break;
			}
		}
	}

	private static boolean dateIsInInterval(int[] weekDaysDatesAsInts,
			int lectureDate) {
		return lectureDate >= weekDaysDatesAsInts[0]
				&& lectureDate <= weekDaysDatesAsInts[6];
	}

	private static int[] computeWeekDaysDatesAsInts(Calendar calendar) {
		int[] weekDaysDatesAsInts = new int[7];
		weekDaysDatesAsInts[0] = getDateAsInt(calendar);
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		weekDaysDatesAsInts[1] = getDateAsInt(calendar);
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		weekDaysDatesAsInts[2] = getDateAsInt(calendar);
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		weekDaysDatesAsInts[3] = getDateAsInt(calendar);
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		weekDaysDatesAsInts[4] = getDateAsInt(calendar);
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		weekDaysDatesAsInts[5] = getDateAsInt(calendar);
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		weekDaysDatesAsInts[6] = getDateAsInt(calendar);
		return weekDaysDatesAsInts;
	}

	private static int getDateAsInt(Calendar calendar) {
		return calendar.get(Calendar.YEAR) * 10000
				+ (calendar.get(Calendar.MONTH) + 1) * 100
				+ calendar.get(Calendar.DAY_OF_MONTH);
		// NOTE: *1000 if time will be used
	}

	private static void setToFirstDayOfWeek(Calendar calendar) {
		while (calendar.get(Calendar.DAY_OF_WEEK) != calendar
				.getFirstDayOfWeek()) {
			calendar.add(Calendar.DAY_OF_MONTH, -1);
		}
	}

}
